package com.sikaryofficial.backend.controller.export;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.sikaryofficial.backend.annotation.TenantFilter;
import com.sikaryofficial.backend.domain.entity.Activity;
import com.sikaryofficial.backend.domain.entity.Prize;
import com.sikaryofficial.backend.manager.export.ActivityDailyExportManager;
import com.sikaryofficial.backend.manager.export.PrizeWinnerExportManager;
import com.sikaryofficial.backend.manager.export.RegisterExportManager;
import com.sikaryofficial.backend.manager.export.WinnerExportManager;
import com.sikaryofficial.backend.service.IActivityService;
import com.sikaryofficial.backend.service.IPrizeService;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.web.controller.BaseController;
import com.sikaryofficial.common.log.annotation.Log;
import com.sikaryofficial.common.log.enums.BusinessType;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.system.api.model.ManualExportReq;
import com.sikaryofficial.system.api.model.download.DownloadUrlDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import static com.sikaryofficial.backend.constant.RedisCacheKey.ACTIVITY_WINNER_EXPORT_STATUS_PREFIX;
import static com.sikaryofficial.backend.constant.RedisCacheKey.EXPORT_STATUS_PREFIX;
import static com.sikaryofficial.backend.constant.RedisCacheKey.PRIZE_WINNER_EXPORT_STATUS_PREFIX;

/**
 * 活动Controller
 *
 * @author qinjinyuan
 * @date 2023-10-27
 */
@RestController
@RequestMapping("/manual")
@Api(tags = "手工导出")
@Slf4j
public class ManualExportController extends BaseController {
    @Autowired
    private WinnerExportManager winnerExportManager;
    @Autowired
    private PrizeWinnerExportManager prizeWinnerExportManager;
    @Autowired
    private ActivityDailyExportManager activityDailyExportManager;
    @Autowired
    private RegisterExportManager registerExportManager;
    @Resource(name = "asyncTaskExecutor")
    private ThreadPoolTaskExecutor asyncTaskExecutor;
    @Autowired
    private RedisService redisService;
    @Autowired
    private IActivityService activityService;
    @Autowired
    private IPrizeService prizeService;
    /**
     * 获奖名单导出
     */
    @GetMapping("/export/winner/{activityId}")
    @ApiOperation("生成获奖名单文件")
    @Log(title = "生成获奖名单", businessType = BusinessType.EXPORT)
    @TenantFilter
    public R<String> createWinnerFileById(@ApiParam(value = "活动id", required = true)
                                          @PathVariable(name = "activityId") Long activityId) {
        try {
            // 判定当前是否有进行中的任务
            Activity activity = activityService.getById(activityId);
            if (Objects.isNull(activity)) {
                throw new ServiceException("the activity is not exist");
            }
            Collection<String> keyList = redisService.keys(ACTIVITY_WINNER_EXPORT_STATUS_PREFIX + "*");
            // 缓存key数量判定 & 并发3个线程进行生成
            if (CollUtil.isNotEmpty(keyList) && keyList.size() > 3) {
                throw new ServiceException("File is generating, please wait ");
            } else {
                CompletableFuture.runAsync(() -> winnerExportManager.createWinnerFileById(activityId), asyncTaskExecutor);
            }
        } catch (Exception e) {
            log.error("productQRDownload:{}", e);
            throw new ServiceException("productQRDownload error." + e.getMessage());
        }
        return R.ok("success");
    }

    @GetMapping("/winner/{activityId}")
    @ApiOperation("下载获奖名单")
    @TenantFilter
    public R<List<DownloadUrlDTO>> queryWinnerFilePath(@ApiParam(value = "活动id", required = true)
                                                       @PathVariable(name = "activityId") Long activityId) {
        return R.ok(winnerExportManager.queryWinnerFilePath(activityId));
    }

    @PostMapping("/export/register")
    @ApiOperation("生成注册明细文件")
    @Log(title = "生成注册明细文件", businessType = BusinessType.EXPORT)
    public R<String> register(@Validated @RequestBody ManualExportReq req) {

        verifyParam(req);
        try {
            // 判定当前是否有进行中的任务
            Collection<String> keyList = redisService.keys(EXPORT_STATUS_PREFIX + "*");
            // 缓存key数量判定 & 并发3个线程进行生成
            if (CollUtil.isNotEmpty(keyList) && keyList.size() > 3) {
                throw new ServiceException("File is generating, please wait ");
            } else {
                CompletableFuture.runAsync(() -> registerExportManager.createFileByParam(req), asyncTaskExecutor);
            }
        } catch (Exception e) {
            log.error("productQRDownload:{}", e);
            throw new ServiceException("productQRDownload error." + e.getMessage());
        }
        return R.ok("success");
    }

    @GetMapping("/register/list")
    @ApiOperation("下载注册名单列表")
    @TenantFilter
    public R<List<DownloadUrlDTO>> registerFileList() {
        return R.ok(registerExportManager.queryDownloadFilePath());
    }

    @PostMapping("/export/activityDaily")
    @ApiOperation("生成日活明细文件")
    @Log(title = "生成日活明细文件", businessType = BusinessType.EXPORT)
    public R<String> activityDaily(@Validated @RequestBody ManualExportReq req) {
        verifyParam(req);
        try {
            // 判定当前是否有进行中的任务
            Collection<String> keyList = redisService.keys(EXPORT_STATUS_PREFIX + "*");
            // 缓存key数量判定 & 并发3个线程进行生成
            if (CollUtil.isNotEmpty(keyList) && keyList.size() > 3) {
                throw new ServiceException("File is generating, please wait ");
            } else {
                CompletableFuture.runAsync(() -> activityDailyExportManager.createFileByParam(req), asyncTaskExecutor);
            }
        } catch (Exception e) {
            log.error("productQRDownload:{}", e);
            throw new ServiceException("productQRDownload error." + e.getMessage());
        }
        return R.ok("success");
    }

    @GetMapping("/activityDaily/list")
    @ApiOperation("下载日活名单列表")
    @TenantFilter
    public R<List<DownloadUrlDTO>> activityDailyFileList() {
        return R.ok(activityDailyExportManager.queryDownloadFilePath());
    }

    /**
     * 判定入参的 开始时间和结束时间，1、开始时间小于结束时间 2、开始和结束时间的差值不能超过1年
     *
     * @param req
     */
    private void verifyParam(ManualExportReq req) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime startTime = LocalDateTimeUtil.parse(req.getStartTime(), formatter);
        LocalDateTime endTime = LocalDateTime.parse(req.getEndTime(), formatter);
        if (startTime.isAfter(endTime)) {
            throw new ServiceException("startTime must be less than endTime");
        }
        long differenceDays = LocalDateTimeUtil.between(startTime, endTime, ChronoUnit.DAYS);
        if (differenceDays > 366) {
            throw new ServiceException("The time difference between startTime and endTime cannot exceed 1 year");
        }
    }

    /**
     * 获奖名单导出
     */
    @GetMapping("/export/prize/winner/{prizeId}")
    @ApiOperation("生成兑奖名单文件")
    @Log(title = "生成兑奖名单", businessType = BusinessType.EXPORT)
    @TenantFilter
    public R<String> createPrizeWinnerFileById(@ApiParam(value = "礼品id", required = true)
                                          @PathVariable(name = "prizeId") Long prizeId) {
        try {
            // 判定当前是否有进行中的任务
            Prize prize = prizeService.getById(prizeId);
            if (Objects.isNull(prize)) {
                throw new ServiceException("the prize is not exist");
            }
            if (!prize.getPrizeType().equals(2)) {
                throw new ServiceException("the prize is err");
            }
            Collection<String> keyList = redisService.keys(PRIZE_WINNER_EXPORT_STATUS_PREFIX + "*");
            // 缓存key数量判定 & 并发3个线程进行生成
            if (CollUtil.isNotEmpty(keyList) && keyList.size() > 3) {
                throw new ServiceException("File is generating, please wait ");
            } else {
                CompletableFuture.runAsync(() -> prizeWinnerExportManager.createWinnerFileById(prizeId), asyncTaskExecutor);
            }
        } catch (Exception e) {
            log.error("productQRDownload:{}", e);
            throw new ServiceException("productQRDownload error." + e.getMessage());
        }
        return R.ok("success");
    }

    @GetMapping("/prize/winner/{prizeId}")
    @ApiOperation("下载兑奖名单")
    @TenantFilter
    public R<List<DownloadUrlDTO>> queryPrizeWinnerFilePath(@ApiParam(value = "礼品id", required = true)
                                                       @PathVariable(name = "prizeId") Long prizeId) {
        return R.ok(prizeWinnerExportManager.queryPrizeWinnerFilePath(prizeId));
    }

}
